﻿Imports System.Net.Sockets
Imports System.Net

Public Class FrmTCPServer
    Dim mStart As Boolean
    Dim mTCPServerList As List(Of TcpListener)
    Dim mTCPClient As List(Of TcpClient)


    Private Sub CloseListener()
        Dim oTCPServer As TcpListener

        ButStart.Text = "开始监听"
        mStart = False

        SyncLock mTCPServerList
            For Each oTCPServer In mTCPServerList
                oTCPServer.Stop()
            Next

            mTCPServerList.Clear()
            LvwServer.Items.Clear()

        End SyncLock

        SyncLock mTCPClient
            For Each oClient As TcpClient In mTCPClient
                oClient.Close
            Next
            mTCPClient.Clear()
        End SyncLock

    End Sub

    Private Sub ButStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButStart.Click
        Dim i As Integer
        Dim oTCPServer As TcpListener
        Dim oLocalIPInfo As IPEndPoint

        If mStart Then
            '关闭TCP
            CloseListener()
        Else
            '启动TCP
            ButStart.Text = "关闭服务"

            Dim lCount As Long = Long.Parse(TxtPortCount.Text)
            Dim lPort As Long = Long.Parse(TxtBeginPort.Text)

            mTCPServerList.Clear()
            mTCPClient.Clear()

            LvwServer.Items.Clear()



            '获取本地监听信息
            Dim ipHostInfo As IPHostEntry = Dns.GetHostEntry(Dns.GetHostName()) '获取本机IP地址
            Dim oLocalIP As IPAddress = ipHostInfo.AddressList(0) '本机IP地址

            For Each oIP As IPAddress In ipHostInfo.AddressList
                If Not oIP.IsIPv6LinkLocal Then
                    oLocalIP = oIP
                    Exit For
                End If
            Next


            For i = 1 To lCount
                Try
                    oTCPServer = New TcpListener(oLocalIP, lPort)
                    oTCPServer.Start()
                    mTCPServerList.Add(oTCPServer)
                    oLocalIPInfo = oTCPServer.LocalEndpoint

                    Dim oItem As ListViewItem
                    oItem = New ListViewItem(oLocalIPInfo.Port.ToString)

                    oItem.SubItems.Add("正在监听")
                    oItem.SubItems.Add("0")
                    LvwServer.Items.Add(oItem)
                Catch ex As SocketException
                    MsgBox(ex.Message)
                End Try

                lPort += 1
            Next

            Dim newThread As New Threading.Thread(AddressOf CheckTCPListener)
            newThread.Name = "数据监测线程"
            newThread.Start()

            mStart = True
        End If

    End Sub

    Private Sub CheckTCPListener()
        Do
            SyncLock mTCPServerList
                If Not mStart Then Exit Do

                Dim oTCPServer As TcpListener
                For Each oTCPServer In mTCPServerList
                    Do While oTCPServer.Pending()
                        Dim oTCPClient As TcpClient = oTCPServer.AcceptTcpClient()
                        AddClient(oTCPClient)
                    Loop
                Next
            End SyncLock

            '检查是否有接收到数据
            SyncLock mTCPClient
                If Not mStart Then Exit Do

                Dim oClient As TcpClient
                Dim i As Integer
                For i = mTCPClient.Count - 1 To 0 Step -1
                    oClient = mTCPClient(i)
                    Do
                        If oClient.Client.Poll(10, SelectMode.SelectRead) Then
                            If oClient.Available = 0 Then


                                Dim oIP As IPEndPoint = oClient.Client.LocalEndPoint
                                ListItemClientValue(False, oIP)

                                oClient.Close()
                                mTCPClient.Remove(oClient)
                                Exit Do
                            Else
                                Dim oStream As NetworkStream = oClient.GetStream
                                Dim bData() As Byte
                                Dim lDataLen As Integer = oClient.Available

                                ReDim bData(lDataLen - 1)

                                lDataLen = oStream.Read(bData, 0, lDataLen)
                                If lDataLen > 0 Then
                                    oStream.Write(bData, 0, lDataLen) '写回去
                                End If
                            End If

                        End If
                    Loop While False
                Next
            End SyncLock
        Loop While mStart
    End Sub

    Private Sub AddClient(ByVal oTCP As TcpClient)
        
        If Not oTCP.Connected Then
            oTCP.Close()
            Return
        End If

        
        SyncLock mTCPClient
            mTCPClient.Add(oTCP)
        End SyncLock

        Dim oSocket As Socket = oTCP.Client

        '设置保活包
        Dim inPar(), outPar(), intbyte() As Byte
        ReDim inPar(11), outPar(50)
        '是否启用Keep-Alive
        inPar(0) = 1
        '多长时间后开始第一次探测（单位：毫秒）
        intbyte = Int32ToByte(1500)
        Array.Reverse(intbyte)
        Array.Copy(intbyte, 0, inPar, 4, 4)
        '探测时间间隔（单位：毫秒）
        intbyte = Int32ToByte(3000)
        Array.Reverse(intbyte)
        Array.Copy(intbyte, 0, inPar, 8, 4)

        Dim rtn As Integer = oSocket.IOControl(IOControlCode.KeepAliveValues, inPar, outPar)

        Dim oIP As IPEndPoint = oSocket.LocalEndPoint


        ListItemClientValue(True, oIP)

    End Sub

    Private Sub ListItemClientValue(ByVal iAdd As Boolean, ByVal oIP As IPEndPoint)
        Me.Invoke(Sub()
                      Dim sPort As String = oIP.Port.ToString
                      For Each oItem As ListViewItem In LvwServer.Items
                          If oItem.Text.Equals(sPort) Then
                              Dim lCount As Long = Long.Parse(oItem.SubItems(2).Text)

                              If iAdd Then
                                  oItem.SubItems(2).Text = lCount + 1
                              Else
                                  If lCount > 0 Then
                                      oItem.SubItems(2).Text = lCount - 1
                                  End If

                              End If


                              Exit For
                          End If
                      Next
                  End Sub)
    End Sub

    Private Sub FrmTCPServer_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
        If mStart Then CloseListener()
    End Sub

    Private Sub FrmTCPServer_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        mTCPServerList = New List(Of TcpListener)
        mTCPClient = New List(Of TcpClient)
    End Sub


    Public Function Int32ToByte(ByVal lValue As UInt32) As Byte()
        Dim b(3) As Byte
        For i = 3 To 0 Step -1
            b(i) = lValue And 255

            lValue = lValue >> 8
            If lValue = 0 Then Exit For
        Next

        Return b
    End Function
End Class
